#ifndef COMMON_H
#define COMMON_H

#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <algorithm>

// StringPool class to manage shared string resources
class StringPool {
public:
    static StringPool& getInstance() {
        static StringPool instance;
        return instance;
    }
    
    // Get or create an index for a string
    int getOrAdd(const std::string& category, const std::string& value) {
        auto& vec = pools_[category];
        auto it = std::find(vec.begin(), vec.end(), value);
        if (it != vec.end()) {
            return static_cast<int>(it - vec.begin());
        }
        
        vec.push_back(value);
        return static_cast<int>(vec.size() - 1);
    }
    
    // Get string value by index
    std::string getValue(const std::string& category, int index) const {
        auto it = pools_.find(category);
        if (it != pools_.end() && index >= 0 && static_cast<size_t>(index) < it->second.size()) {
            return it->second[index];
        }
        return "";
    }
    
    // Get all strings in a category
    const std::vector<std::string>& getStrings(const std::string& category) const {
        static const std::vector<std::string> empty;
        auto it = pools_.find(category);
        if (it != pools_.end()) {
            return it->second;
        }
        return empty;
    }
    
    // Clear all pools
    void clear() {
        pools_.clear();
    }
    
private:
    StringPool() {}
    std::unordered_map<std::string, std::vector<std::string>> pools_;
    
    // Singleton pattern - disallow copying
    StringPool(const StringPool&) = delete;
    StringPool& operator=(const StringPool&) = delete;
};

// Common structures used across the project
struct GNSSObservation {
    // Basic information
    double time;               // Observation time
    int satellite;             // Satellite identifier index
    int system;                // Satellite system index (G, R, E, C...)
    int station;               // Station name index
    double elevation;          // Elevation angle
    double azimuth;            // Azimuth angle
    
    // Observation values
    double P1;                 // Pseudorange 1
    double P2;                 // Pseudorange 2
    double L1;                 // Carrier phase 1
    double L2;                 // Carrier phase 2
    double f1;                 // Frequency 1
    double f2;                 // Frequency 2
    std::map<int, double> obsValues;  // Raw observation values (obsType index -> value)
    
    // Status and quality indicators
    bool hasCycleSlip = false; // Cycle slip flag
    bool hasMultipath = false; // Multipath flag
    double multipathIndex = 0.0; // Multipath index
    double snr = 0.0;          // Signal-to-noise ratio
    double weight = 1.0;       // Observation weight
    int epochIndex = 0;        // Epoch index
    
    // Satellite geometry
    std::vector<double> satellitePosition;  // XYZ position of satellite
    std::vector<double> stationPosition;    // XYZ position of receiver station
    std::vector<double> lineOfSight;        // Unit vector from receiver to satellite
    
    // Helper methods to work with string equivalents
    std::string getSatellite() const {
        return StringPool::getInstance().getValue("satellites", satellite);
    }
    
    std::string getSystem() const {
        return StringPool::getInstance().getValue("systems", system);
    }
    
    std::string getStation() const {
        return StringPool::getInstance().getValue("stations", station);
    }
    
    double getObsValue(const std::string& obsType) const {
        int typeIndex = StringPool::getInstance().getOrAdd("obstypes", obsType);
        auto it = obsValues.find(typeIndex);
        return (it != obsValues.end()) ? it->second : 0.0;
    }
    
    void setObsValue(const std::string& obsType, double value) {
        int typeIndex = StringPool::getInstance().getOrAdd("obstypes", obsType);
        obsValues[typeIndex] = value;
    }
    
    // Static methods for string pool management
    static int addSatellite(const std::string& sat) {
        return StringPool::getInstance().getOrAdd("satellites", sat);
    }
    
    static int addSystem(const std::string& sys) {
        return StringPool::getInstance().getOrAdd("systems", sys);
    }
    
    static int addStation(const std::string& sta) {
        return StringPool::getInstance().getOrAdd("stations", sta);
    }
    
    static int addObsType(const std::string& obs) {
        return StringPool::getInstance().getOrAdd("obstypes", obs);
    }
    
    static int getObsTypeIndex(const std::string& obsType) {
        return StringPool::getInstance().getOrAdd("obstypes", obsType);
    }
    
    static std::vector<std::string> getAllSatellites() {
        return StringPool::getInstance().getStrings("satellites");
    }
    
    static std::vector<std::string> getAllSystems() {
        return StringPool::getInstance().getStrings("systems");
    }
    
    static std::vector<std::string> getAllStations() {
        return StringPool::getInstance().getStrings("stations");
    }
    
    static std::vector<std::string> getAllObsTypes() {
        return StringPool::getInstance().getStrings("obstypes");
    }
};

struct StationInfo {
    std::string name;      // Station name
    std::string id;        // Station ID
    std::string markerName;
    double x, y, z;        // Cartesian coordinates
    double lat, lon, height;   // Geodetic coordinates (WGS-84)
    double latitude;       // Alternative name for lat (for compatibility)
    double longitude;      // Alternative name for lon (for compatibility)
    std::string recType;   // Receiver type
    std::string antType;   // Antenna type
};

#endif // COMMON_H 